import math
import numpy as np
import data_inputer
from mealpy import FloatVar, GA, Optimizer
import threading
from map_manager import MapManager
from node_class import Node
import time
_START_POS=2
_END_POS=26
nodes_data=data_inputer.NODES_DATA
res:list
def get_max_neighboors_count(nodes_data:dict):
    max=-1
    for node in nodes_data.values():
        node:Node
        nei_count=len(node.neighbors)
        if(max<nei_count):
            max=nei_count
    return max
def objective_function(solution):
        global _START_POS,_END_POS,res
        res=[]
        score=0
        dst_solution=[]
        for id in solution:
             dst_solution.append(int(id))
        solution=dst_solution
        node_ptr=nodes_data[_START_POS]
        for i in range(len(solution)):
            res.append(node_ptr.id)
            if(node_ptr.id==_END_POS):
                #print(res)
                return score+len(res)*10
            else:
                count=solution[i]%len(node_ptr.neighbors)
                nei=node_ptr.neighbors.copy()
                for id in res:
                    try:
                        nei.pop(id)
                    except:
                        pass
                    
                if(len(nei)==0):
                     #print(res,"dead")
                     return score+1000/len(res)+1000       
                nei_list=list(nei.items())
                #print(nei_list)

                count=solution[i]%len(nei)
                #print(count)
                key,value=nei_list[count]
                node_ptr=nodes_data[key]

                score+=value   
        return score+100000           


def GA_Touch(nodes_data:dict,start_id:int,end_id:int):
    '''
    迭代和种群数量设置的非常短，用于快速评价距离
    '''
    return GA_Core(nodes_data,epoch=10,pop_size=50,start_id=start_id,end_id=end_id)
def GA_Core(nodes_data:dict,epoch=100, pop_size=200, pc=0.9, pm=0.05,start_id=None,end_id=None):
    if(start_id!=None and end_id!=None):
        global _START_POS,_END_POS
        _START_POS=start_id
        _END_POS=end_id
    problem = {
        "obj_func": objective_function,
        #"bounds": FloatVar(lb=[0]*30, ub=[math.factorial(get_max_neighboors_count(nodes_data))]*30),
        "bounds": FloatVar(lb=[0]*30, ub=[math.lcm(*range(1,get_max_neighboors_count(nodes_data)))]*30),
        "minmax": "min",
    }
    models = [
        GA.BaseGA(epoch, pop_size, pc, pm),
    ]
    for model in models:
        g_best = model.solve(problem)
        objective_function(g_best.solution)
        # model.history.save_global_objectives_chart(filename="goc")
        # model.history.save_local_objectives_chart(filename="loc")
        return res[-1]==_END_POS,res,g_best.target.fitness-len(res)*10
def GAThreadFunction():
    global nodes_data
    while True:
        # roads=[1,2,3,4,5]
        # time.sleep(1)
        roads=GA_Core(nodes_data)
        MapManager.instance.DrawRoad(roads)

# GA_Thread=threading.Thread(name="ga_thread",target=GAThreadFunction)
# roads=GA_Touch(nodes_data,2,70)
# print(roads)
# print(math.factorial(get_max_neighboors_count(nodes_data)))
